package org.zsk.fastdev.bean;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.thymeleaf.util.MapUtils;
import org.zsk.fastdev.annotations.FieldMap;
import org.zsk.fastdev.annotations.enumration.SqlComparator;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *     bean工具类
 * </p>
 *
 * @author zsk
 * @version 1.0
 * Created on 2020/5/29
 */
public class BeanUtils {

    /**
     * 获取bean的所有getter方法
     * @param sourceClazz 源clazz
     * @return 所有符合条件的getter方法
     */
    public static List<Method> getters(Class<?> sourceClazz){
        return Arrays.stream(sourceClazz.getMethods()).filter(method -> {
            return method.getName().startsWith("get") && Modifier.isPublic(method.getModifiers())
                    && !method.getName().equals("getClass");
        }).collect(Collectors.toList());
    }

    /**
     * 根据getter方法获取对应的参数
     * @param getter getter方法
     * @return getter对应的参数
     */
    public static String getFieldNameByGetter(Method getter){
        String rmGet=getter.getName().substring(3);
        return Character.toLowerCase(rmGet.charAt(0))+rmGet.substring(1);
    }

    /**
     * 获取字段名称
     * @param field 属性
     * @return 该属性字段名称
     */
    public static String getColumnName(String field) {
        return Arrays.stream(field.split("")).collect(StringBuilder::new,(stringBuilder, s) -> {
            if(Character.isLowerCase(s.charAt(0))) {
                stringBuilder.append(s);
            }else {
                stringBuilder
                        .append("_")
                        .append(s.toLowerCase());
            }
        },StringBuilder::append).toString();
    }

    /**
     * bean转换为queryWrapper
     * @param beanClazz bean的class
     * @param bean bean实例
     * @param <T> bean类型
     * @return bean对应的queryWrapper实例
     * @throws Exception 转换错误
     */
    public static <T> QueryWrapper<T> bean2QueryWrapper(Class<T> beanClazz,Object bean) throws Exception {
        Class<?> queryClazz= QueryWrapper.class;
        Object query=queryClazz.getConstructor().newInstance();
        List<Method> methodList=BeanUtils.getters(beanClazz);
        methodList.stream().filter(method -> {
            try {
                return Objects.nonNull(method.invoke(bean));
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
            return false;
        }).forEach(method -> {
            try {
                Field field=beanClazz.getDeclaredField(getFieldNameByGetter(method));
                Annotation fieldMap=field.getAnnotation(FieldMap.class);
                Method comparatorMethod;
                if (Objects.nonNull(fieldMap)){
                    //获取比较方法
                    String comparator= (String) fieldMap.annotationType().getMethod(FieldMap.COMPARATOR).invoke(fieldMap);
                    comparatorMethod=queryClazz.getMethod(SqlComparator.symbol2Method(comparator),Object.class,Object.class);
                }else {
                    //默认等于
                    comparatorMethod=queryClazz.getMethod(SqlComparator.EQ.getMethod(),Object.class,Object.class);
                }
                comparatorMethod.invoke(query,getColumnName(getFieldNameByGetter(method)),method.invoke(bean));
            } catch (IllegalAccessException | InvocationTargetException | NoSuchFieldException | NoSuchMethodException e) {
                e.printStackTrace();
            }
        });
        return (QueryWrapper<T>) query;
    }

    /**
     * 判断对象逻辑空
     * @param object 任意对象
     * @return 是否逻辑空
     */
    public static boolean isLogicalEmptyObject(Object object){
        //是否集合
        if (object instanceof Collection){
            return CollectionUtils.isEmpty((Collection<?>) object);
        }else if(object instanceof Map){
            return MapUtils.size((Map<?, ?>) object)==0;
        }else{
            return (object == null || "".equals(object));
        }
    }
}
